package com.lz.autotest.project.testmanage.autoTest.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.lz.autotest.common.constant.ListenerTypeConstants;
import com.lz.autotest.common.constant.ReportStatusConstants;
import com.lz.autotest.common.constant.ReportTypeConstants;
import com.lz.autotest.common.constant.ThreadTypeConstants;
import com.lz.autotest.common.entity.ResponseVo;
import com.lz.autotest.common.utils.*;
import com.lz.autotest.common.web.domain.TreeSelect;
import com.lz.autotest.project.testmanage.autoTest.entity.InfResultVo;
import com.lz.autotest.project.testmanage.autoTest.entity.TsstAutotestItem;
import com.lz.autotest.project.testmanage.autoTest.entity.TsstAutotestMenu;
import com.lz.autotest.project.testmanage.autoTest.mapper.TsstAutotestItemMapper;
import com.lz.autotest.project.testmanage.autoTest.mapper.TsstAutotestMenuMapper;
import com.lz.autotest.project.testmanage.autoTest.service.Engine.StandardXtsEngine;
import com.lz.autotest.project.testmanage.autoTest.service.Listener.CalcServiceListener;
import com.lz.autotest.project.testmanage.autoTest.service.Listener.DownloadDataListener;
import com.lz.autotest.project.testmanage.autoTest.service.Listener.Listener;
import com.lz.autotest.project.testmanage.autoTest.service.Listener.SendDataListener;
import com.lz.autotest.project.testmanage.autoTest.service.TsstAutotestMenuService;
import com.lz.autotest.project.testmanage.autoTest.service.thread.ThreadContext;

import com.lz.autotest.common.holder.ContextHolder;
import com.lz.autotest.project.testmanage.infmanage.domain.SstInf;
import com.lz.autotest.project.testmanage.reportmanage.domain.SstInfReport;
import com.lz.autotest.project.testmanage.reportmanage.mapper.InfReportMapper;
import com.lz.autotest.project.testmanage.envmanage.service.TsstEnvService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: X
 * @date: Created in 2023/6/14 16:49
 * @Description:
 */
@Service
public class TsstAutotestMenuServiceImpl implements TsstAutotestMenuService {

    @Resource
    private TsstAutotestMenuMapper txtsTestMenuMapper;

    @Resource
    private TsstAutotestItemMapper tsstAutotestItemMapper;

    @Resource
    private InfReportMapper infReportMapper;


    @Resource
    private TsstEnvService tsstEnvService;

    //生成报告ID
    Snowflake snowflake = IdUtil.getSnowflake(1, 3);

    @Override
    public ResponseVo insert(TsstAutotestMenu TsstAutotestMenu) {
        // valid
        if (TsstAutotestMenu == null) {
            return ResponseVo.failure("必要参数缺失");
        }
        txtsTestMenuMapper.insert(TsstAutotestMenu);
        return ResponseVo.success();
    }


    @Override
    public ResponseVo delete(Map<String, Object> param) {
        Map<String, Object> map = new HashMap<>();
        map.put("parentId", param.get("menuId"));
        List<TsstAutotestMenu> menu = txtsTestMenuMapper.selectAllMenu(map);
        if (!menu.isEmpty()) {
            return ResponseVo.failure("目录存在子目录或者测试场景，不能删除!");
        }
        int ret = txtsTestMenuMapper.delete(param);
        return ret > 0 ? ResponseVo.success() : ResponseVo.failure();
    }


    @Override
    public ResponseVo update(TsstAutotestMenu tsstAutotestMenu) {
        Long menuId = tsstAutotestMenu.getMenuId();
        String status = tsstAutotestMenu.getStatus();
        List<SstInf> infs = tsstAutotestMenu.getInfList();
        if (infs != null && !infs.isEmpty()) {
            tsstAutotestItemMapper.delete(menuId);
            List<TsstAutotestItem> tsstAutotestItems = new ArrayList<>();
            for (SstInf inf : infs) {
                TsstAutotestItem tsstAutotestItem = new TsstAutotestItem();
                tsstAutotestItem.setMenuId(menuId);
                tsstAutotestItem.setInfId(Long.parseLong(inf.getInfId()));
                tsstAutotestItem.setStatus(status);
                tsstAutotestItem.setCreateBy(SecurityUtils.getUsername());
                tsstAutotestItems.add(tsstAutotestItem);
            }
            if (!tsstAutotestItems.isEmpty()) {
                tsstAutotestItemMapper.batchInsetATI(tsstAutotestItems);
            }
        }
        int ret = txtsTestMenuMapper.update(tsstAutotestMenu);
        return ret > 0 ? ResponseVo.success() : ResponseVo.failure();
    }


    @Override
    public TsstAutotestMenu load(int id) {
        return txtsTestMenuMapper.load(id);
    }

    @Override
    public List<TsstAutotestMenu> selectAllMenu(Map<String, Object> param) {
        return txtsTestMenuMapper.selectAllMenu(param);
    }

    @Override
    public List<TreeSelect> buildSstInfTreeSelect(List<TsstAutotestMenu> tsstTestMenus) {
        List<TsstAutotestMenu> deptTrees = buildsstTestMenuTree(tsstTestMenus);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    @Override
    public ResponseVo autoTestRun(TsstAutotestMenu tsstAutotestMenu) {
        tsstAutotestMenu.setReportId(snowflake.nextIdStr());
        tsstAutotestMenu.setCalcTime(DateUtils.getCurr_YYYY_MM_DD_HH_MM_SS());
        GlobalMap.putInfResultVo(tsstAutotestMenu.getReportId(), new InfResultVo());

        tsstAutotestMenu.setCreateBy(SecurityUtils.getUsername());
        SstInfReport report = builderSstInfReport(tsstAutotestMenu);
        tsstAutotestMenu.setRequestIp(ContextHolder.getParam().get("ip").toString());
        // 对于数据进行处理
        requestByEntry(tsstAutotestMenu);
        infReportMapper.saveInfReport(report);
        return ResponseVo.success(tsstAutotestMenu.getReportId());
    }

    //创建报告对象
    private SstInfReport builderSstInfReport(TsstAutotestMenu tsstAutotestMenu) {
        SstInfReport report = new SstInfReport();
        report.setReportId(tsstAutotestMenu.getReportId());
        report.setReportType(ReportTypeConstants.BATCH);
        report.setMenuId(tsstAutotestMenu.getMenuId());
        report.setInfId(tsstAutotestMenu.getInfList().size() == 1 ? tsstAutotestMenu.getInfList().get(0).getInfId() : null);
        report.setReportName(tsstAutotestMenu.getMenuName() + "_" + tsstAutotestMenu.getCalcTime());
        report.setCalcDate(DateUtils.getCurr_YYYY_MM_DD());
        report.setRequestTime(tsstAutotestMenu.getCalcTime());
        report.setCreateBy(tsstAutotestMenu.getCreateBy());
        report.setInfEnv(tsstAutotestMenu.getRunEnv());
        report.setConcurrency(tsstAutotestMenu.getThreadNumber());
        report.setRound((int) tsstAutotestMenu.getCycleNumber());
        report.setInfMethod(tsstAutotestMenu.getInfList().stream()
                .map(SstInf::getInfName)
                .collect(Collectors.joining(",")));
        report.setInfUrl(tsstAutotestMenu.getInfList().stream()
                .map(SstInf::getInfUrl)
                .collect(Collectors.joining(",")));
        report.setReportSource(tsstAutotestMenu.getReportSource());
        report.setStatus(ReportStatusConstants.BEGIN);
        report.setReportVersion(tsstAutotestMenu.getReportVersion());
        return report;
    }

    private void requestByEntry(TsstAutotestMenu tsstAutotestMenu) {
        List<SstInf> sstInfs;
        sstInfs = tsstAutotestMenu.getInfList();
        //设置真实环境地址
        for (SstInf sstInf : sstInfs) {
            sstInf.setRecordVersion(tsstAutotestMenu.isRecordVersion());
            sstInf.setInfEnv(tsstAutotestMenu.getRunEnv());
            sstInf.setInfRealEnv(tsstEnvService.selectTsstEnvByEnvId(Long.valueOf(sstInf.getInfEnv())));
        }
        StandardXtsEngine standardXtsEngine = new StandardXtsEngine();
        //添加netty监听器
        List<Listener> listeners = new ArrayList<>();
        listeners.add(new SendDataListener(ListenerTypeConstants.SEND_DATA, 1));
        listeners.add(new DownloadDataListener(ListenerTypeConstants.DOWNLOAD_DATA, 2));
        listeners.add(new CalcServiceListener(ListenerTypeConstants.CALC_SERVER_DATA, 3));

        ThreadContext threadContext = new ThreadContext.Builder()
                .setThreadType(ThreadTypeConstants.AUTO_TEST_ENTRY)
                .setListeners(listeners)
                .setSstInfs(sstInfs)
                .setCycleNumber(tsstAutotestMenu.getCycleNumber())
                .setTsstAutotestMenu(tsstAutotestMenu)
                .build();
        standardXtsEngine.configure(tsstAutotestMenu.getThreadNumber(), threadContext);
        GlobalMap.putEngine(tsstAutotestMenu.getReportId(), standardXtsEngine);
        standardXtsEngine.runTest();
    }

    private List<TsstAutotestMenu> buildsstTestMenuTree(List<TsstAutotestMenu> tsstTestMenus) {
        List<TsstAutotestMenu> returnList = new ArrayList<>();
        List<Long> tempList = new ArrayList<>();
        for (TsstAutotestMenu item : tsstTestMenus) {
            tempList.add(item.getMenuId());
        }
        for (TsstAutotestMenu next : tsstTestMenus) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(next.getParentId())) {
                recursionFn(tsstTestMenus, next);
                returnList.add(next);
            }
        }
        if (returnList.isEmpty()) {
            returnList = tsstTestMenus;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<TsstAutotestMenu> list, TsstAutotestMenu t) {
        // 得到子节点列表
        List<TsstAutotestMenu> childList = getChildList(list, t);
        t.setChildren(childList);
        for (TsstAutotestMenu tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<TsstAutotestMenu> getChildList(List<TsstAutotestMenu> list, TsstAutotestMenu t) {
        List<TsstAutotestMenu> tlist = new ArrayList<>();
        Iterator<TsstAutotestMenu> it = list.iterator();
        while (it.hasNext()) {
            TsstAutotestMenu n = (TsstAutotestMenu) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().equals(t.getMenuId())) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<TsstAutotestMenu> list, TsstAutotestMenu t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }
}
